home *** CD-ROM | disk | FTP | other *** search
/ AppleScript - The Beta Release / AppleScript - The Beta Release.iso / Documentation / develop / Better Apple Event Coding / Code Samples / UAppleObject.cp < prev    next >
Encoding:
Text File  |  1992-10-16  |  13.4 KB  |  613 lines  |  [TEXT/MPS ]

  1. // UAppleObject.cp
  2. // by Eric Berdahl
  3. // AppleLink: BERDAHL
  4. // Interget: eric_berdahl@taligent.com
  5. // May XX, 1992
  6. //
  7. // Copyright © 1992 Eric M. Berdahl
  8. // All rights reserved.
  9. //
  10. // LICENSE
  11. //
  12. // UAppleObject is provided under the ego-ware™ system.  If you send me a note
  13. // telling me how cool you think it UAppleObject is, you may incorporate it into
  14. // any product you like (six-packs of good beer are also acceptable, no C.O.D.
  15. // shipments, please).  Also, you must keep all copyright and other notices in
  16. // the source code, especially MY NAME (The system is called ego-ware™.  Get it?).
  17.  
  18.  
  19. #ifndef __AEOBJECTS__
  20. #include <AEObjects.h>
  21. #endif
  22.  
  23. #ifndef    __EXCEPTIONS__
  24. #include "Exceptions.h"
  25. #endif
  26.  
  27. #ifndef __RESOURCES__
  28. #include <Resources.h>
  29. #endif
  30.  
  31. #ifndef _UAPPLEOBJECT_
  32. #include "UAppleObject.h"
  33. #endif
  34.  
  35. #ifndef    __UMAFAILURE__
  36. #include "UMAFailure.h"
  37. #endif
  38.  
  39.  
  40. // This unit requires a definition for DEBUG (indicating whether or not you
  41. // want debugging code compiled in).  If you don’t set the flag, I’ll just 
  42. // assume you don’t want any.
  43. #ifndef DEBUG
  44. #define    DEBUG 0
  45. #endif
  46.  
  47. //--------------------------------------------------------------------------------
  48. // TAppleObjectDispatcher
  49. //--------------------------------------------------------------------------------
  50.  
  51. TAppleObjectDispatcher* TAppleObjectDispatcher::fgDispatcher = nil;
  52. Boolean TAppleObjectDispatcher::fgInited = false;
  53.  
  54.  
  55. TAppleObjectDispatcher::TAppleObjectDispatcher()
  56. {
  57.     fDisposalList = nil;
  58.     fDisposalListSize = 0;
  59.     fApplication = nil;
  60. }
  61.  
  62.  
  63. TAppleObjectDispatcher::~TAppleObjectDispatcher()
  64. {
  65.     if (fDisposalList != nil)
  66.         DisposeHandle((Handle) fDisposalList);
  67. }
  68.  
  69. struct MAEventTableRec
  70. {
  71.     OSType theClass;
  72.     OSType theID;
  73.     long theValue;
  74. };
  75. typedef MAEventTableRec* MAEventTablePointer;
  76.  
  77. void TAppleObjectDispatcher::Install()
  78. {
  79.     if (fgDispatcher != nil)
  80.         FailOSErr(errAppleObjectDispatcherAlreadyInstalled);
  81.  
  82.     TRY
  83.     {
  84.         if (!fgInited)
  85.         {
  86.             AEObjectInit();
  87.             fgInited = true;
  88.         }
  89.  
  90.         fgDispatcher = this;
  91.  
  92.         // Install AppleEvent handlers from all aedt resources
  93.         // Look for all AppleEvent dispatch tables… 
  94.         short numberOfTables = Count1Resources('aedt');
  95.         FailResError();
  96.  
  97.         for (short tableIndex = 1; tableIndex <= numberOfTables; ++tableIndex)
  98.         {
  99.             Handle tableHandle = Get1IndResource('aedt', tableIndex);
  100.             TRY
  101.             {
  102.                 FailResError();
  103.  
  104.                 SignedByte savedState = HGetState(tableHandle);
  105.                 HLockHi(tableHandle);
  106.  
  107.                 long tableSize = GetHandleSize(tableHandle);
  108.                 FailMemError();
  109.  
  110.                 short tableElements = (short)(tableSize / sizeof(MAEventTableRec));
  111.  
  112.                 MAEventTablePointer tablePtr = (MAEventTablePointer) *tableHandle;
  113.  
  114.                 // Install a single event handler for all events 
  115.                 for (short eventIndex = 1; eventIndex <= tableElements; ++eventIndex, ++tablePtr)
  116.                     this->InstallAppleEventHandler(tablePtr->theClass, tablePtr->theID, tablePtr->theValue);
  117.  
  118.                 HSetState(tableHandle, savedState);
  119.             }
  120.             RECOVER
  121.             {
  122.                 if (tableHandle)
  123.                     ReleaseResource(tableHandle);
  124.             }
  125.             ENDTRY
  126.  
  127.             ReleaseResource(tableHandle);
  128.         }
  129.  
  130.  
  131.  
  132.  
  133.             // Install a universal object accessor
  134.         FailOSErr(AEInstallObjectAccessor(typeWildCard, typeWildCard,
  135.                                    TAppleObjectDispatcher::OSLObjectAccessorHandler,
  136.                                    0, false));
  137.  
  138.             // Set up the object support library callbacks
  139.         FailOSErr(AESetObjectCallbacks(
  140.                             TAppleObjectDispatcher::OSLCompareObjectsHandler,
  141.                             TAppleObjectDispatcher::OSLCountObjectsHandler,
  142.                             TAppleObjectDispatcher::OSLDisposeTokenHandler,    
  143.                             nil, nil, nil, nil));
  144.     }
  145.     RECOVER
  146.     {
  147.         fgDispatcher = nil;
  148.     }
  149.     ENDTRY
  150. }
  151.  
  152.  
  153. MAppleObject* TAppleObjectDispatcher::ExtractObject(const AEDesc& descriptor)
  154. {
  155.     MAppleObject* result;
  156.  
  157.     if (descriptor.descriptorType == typeNull)
  158.         result = MAppleObject::GetDefaultAppleObject();
  159.     else
  160.         result = (MAppleObject*)descriptor.dataHandle;
  161.  
  162. #if DEBUG
  163.         if (descriptor.descriptorType != result->GetAppleClass())
  164.             DebugStr((ConstStr255Param) "Protocol error: object isn’t what it says it is");
  165. #endif
  166.  
  167.     return result;
  168. }
  169.  
  170.  
  171. MAppleObject* TAppleObjectDispatcher::GetTarget(const AppleEvent& message)
  172. {
  173.     // The target defaults to the application
  174.     MAppleObject* result = MAppleObject::GetDefaultAppleObject();
  175.  
  176.     TRY
  177.     {
  178.         AEDesc    theDirectParameter;
  179.         FailOSErr(AEGetParamDesc(&message, keyDirectObject, typeWildCard, &theDirectParameter));
  180.         TRY
  181.         {
  182.             // If the direct object is an object specifier, resolve it into
  183.             // an application domain object.
  184.             if (theDirectParameter.descriptorType == typeObjectSpecifier)
  185.                 result = this->ResolveSpecifier(theDirectParameter);
  186.         }
  187.         RECOVER
  188.         {
  189.             OSErr ignoreErr = AEDisposeDesc(&theDirectParameter);
  190.         }
  191.         ENDTRY
  192.     }
  193.     RECOVER
  194.     {
  195.         // It’s all right for there to be no direct object.  In that
  196.         // case, we stick with the default.
  197.         if (gFailError == errAEDescNotFound)
  198.             goto NoDescriptor;
  199.     }
  200.     ENDTRY
  201.  
  202. NoDescriptor:
  203.     FailNIL(result);
  204.  
  205.     return result;
  206. }
  207.  
  208.  
  209. void TAppleObjectDispatcher::StuffDescriptor(AEDesc& descriptor,
  210.                                              MAppleObject* object)
  211. {
  212.     descriptor.descriptorType = object->GetAppleClass();
  213.     descriptor.dataHandle = (Handle) object;
  214. }
  215.  
  216.  
  217. void TAppleObjectDispatcher::HandleAppleEvent(const AppleEvent& message,
  218.                                   AppleEvent& reply,
  219.                                   long refCon)
  220. {
  221.     MAppleObject* theTarget = this->GetTarget(message);
  222.     theTarget->DoAppleEvent(message, reply, refCon);
  223.  
  224.     // Dispose of the token object
  225.     AEDesc    fakeToken;
  226.     this->StuffDescriptor(fakeToken, theTarget);
  227.     FailOSErr(AEDisposeToken(&fakeToken));
  228. }
  229.  
  230.  
  231. void TAppleObjectDispatcher::AccessContainedObjects(DescType desiredClass,
  232.                                         const AEDesc& container,
  233.                                         DescType containerClass,
  234.                                         DescType form,
  235.                                         const AEDesc& selectionData,
  236.                                         AEDesc& value,
  237.                                         long /* refCon */)
  238. {
  239.     MAppleObject* containerObject = this->ExtractObject(container);
  240.  
  241. #if DEBUG
  242.         if (containerObject->GetAppleClass() != containerClass)
  243.             DebugStr((ConstStr255Param) "Protocol error: object isn’t what the AE Manager thinks it is");
  244. #endif
  245.  
  246.     Boolean    needsDisposal;
  247.     MAppleObject* resultObject = containerObject->GetContainedObject(desiredClass,
  248.                                                         form, selectionData,
  249.                                                         needsDisposal);
  250.     if (resultObject == nil)
  251.         FailOSErr(errAENoSuchObject);
  252.  
  253.     this->StuffDescriptor(value, resultObject);
  254.  
  255.     if (needsDisposal)
  256.         this->SetTokenObjectDisposal(resultObject, true);
  257. }
  258.  
  259.  
  260. long TAppleObjectDispatcher::CountObjects(const AEDesc& containerToken,
  261.                               DescType countObjectsOfType)
  262. {
  263.     MAppleObject* containerObject = this->ExtractObject(containerToken);
  264.     return containerObject->CountContainedObjects(countObjectsOfType);
  265. }
  266.  
  267. Boolean TAppleObjectDispatcher::CompareObjects(DescType operation,
  268.                                                const AEDesc& obj1,
  269.                                                const AEDesc& obj2)
  270. {
  271.     MAppleObject*    mObj1 = this->ExtractObject(obj1);
  272.     MAppleObject*    mObj2 = this->ExtractObject(obj2);
  273.  
  274.     return mObj1->CompareAppleObjects(operation, *mObj2);
  275. }
  276.  
  277. void TAppleObjectDispatcher::DisposeToken(AEDesc& unneededToken)
  278. {
  279.     MAppleObject*    theObject = this->ExtractObject(unneededToken);
  280.     if (this->GetTokenObjectDisposal(theObject))
  281.         delete theObject;
  282. }
  283.  
  284.  
  285. Boolean TAppleObjectDispatcher::GetTokenObjectDisposal(const MAppleObject* theObject)
  286. {
  287.     Boolean    result = false;
  288.  
  289.     // Search the list of objects to be disposed.  Return true if the object is
  290.     // in the list.
  291.     MAppleObject** curObj = *fDisposalList;
  292.     for (long i = 0; i < fDisposalListSize; i++, curObj++)
  293.     {
  294.         if (theObject == *curObj)
  295.         {
  296.             result = true;
  297.             break;
  298.         }
  299.     }
  300.  
  301.     return result;
  302. }
  303.  
  304.  
  305. void TAppleObjectDispatcher::SetTokenObjectDisposal(MAppleObject* theObject,
  306.                                                Boolean needsDisposal)
  307. {
  308.     // Search the list of objects to be disposed to see if it currently exists.
  309.     Boolean nilFound = false;
  310.     Boolean    found = false;
  311.     MAppleObject** curObj = *fDisposalList;
  312.     for (long i = 0; i < fDisposalListSize; i++, curObj++)
  313.     {
  314.         if (theObject == *curObj)
  315.         {
  316.             found = true;
  317.  
  318.             if (!needsDisposal)
  319.                 // remove it from the disposal list
  320.                 *curObj = nil;
  321.  
  322.             break;
  323.         }
  324.         else if (*curObj == nil)
  325.             nilFound = true;
  326.     }
  327.  
  328.     if (!found  &&  needsDisposal)
  329.     {
  330.         // it needs to be added to the list
  331.  
  332.         if (nilFound)
  333.         {
  334.             // we can sneak into a nil spot
  335.             curObj = *fDisposalList;
  336.             for (i = 0; i < fDisposalListSize; i++, curObj++)
  337.             {
  338.                 if (*curObj == nil)
  339.                 {
  340.                     *curObj = theObject;
  341.                     break;
  342.                 }
  343.             }
  344.         }
  345.         else
  346.         {
  347.             // If the list hasn’t been created yet, create a zero-sized list
  348.             if (fDisposalList == nil)
  349.             {
  350.                 fDisposalList = (MAppleObject***) NewHandle(0);
  351.                 FailNIL(fDisposalList);
  352.             }
  353.  
  354.             TRY
  355.             {
  356.                 fDisposalListSize++;
  357.                 SetHandleSize((Handle) fDisposalList, fDisposalListSize*sizeof(MAppleObject*));
  358.                 FailMemError();
  359.                 curObj = *fDisposalList;
  360.                 curObj += fDisposalListSize - 1;
  361.                 *curObj = theObject;
  362.             }
  363.             RECOVER
  364.             {
  365.                 fDisposalListSize--;
  366.             }
  367.             ENDTRY
  368.         }
  369.     }
  370. }
  371.  
  372.  
  373. MAppleObject* TAppleObjectDispatcher::ResolveSpecifier(AEDesc& objectSpecifier)
  374. {
  375.     AEDesc    tokenDesc;
  376.     FailOSErr(AEResolve(&objectSpecifier, kAEIDoMinimum, &tokenDesc));
  377.     MAppleObject* result = this->ExtractObject(tokenDesc);
  378.     return result;
  379. }
  380.  
  381.  
  382. pascal OSErr TAppleObjectDispatcher::AppleEventHandler(const AppleEvent* message,
  383.                                           AppleEvent* reply,
  384.                                           long refCon)
  385. {
  386.     OSErr    result = noErr;
  387.  
  388.     TRY
  389.     {
  390.         GetDispatcher()->HandleAppleEvent(*message, *reply, refCon);
  391.     }
  392.     RECOVER
  393.     {
  394.         result = gFailError;
  395.         goto ReturnErrorCode;
  396.     }
  397.     ENDTRY
  398.  
  399. ReturnErrorCode:
  400.     return result;
  401. }
  402.  
  403. pascal OSErr TAppleObjectDispatcher::OSLObjectAccessorHandler(DescType desiredClass,
  404.                                          const AEDesc* container,
  405.                                          DescType containerClass,
  406.                                          DescType form,
  407.                                          const AEDesc* selectionData,
  408.                                          AEDesc* value,
  409.                                          long refCon)
  410. {
  411.     OSErr    result = noErr;
  412.  
  413.     TRY
  414.     {
  415.         GetDispatcher()->AccessContainedObjects(desiredClass, *container,
  416.                                                 containerClass, form,
  417.                                                 *selectionData,
  418.                                                 *value, refCon);
  419.     }
  420.     RECOVER
  421.     {
  422.         result = gFailError;
  423.         goto ReturnErrorCode;
  424.     }
  425.     ENDTRY
  426.  
  427. ReturnErrorCode:
  428.     return result;
  429. }
  430.  
  431. pascal OSErr TAppleObjectDispatcher::OSLCountObjectsHandler(DescType countObjectsOfType,
  432.                                             DescType /* containerClass */,
  433.                                             const AEDesc* containerToken,
  434.                                             long* result)
  435. {
  436.     OSErr    theErr = noErr;
  437.  
  438.     TRY
  439.     {
  440.         *result = GetDispatcher()->CountObjects(*containerToken, countObjectsOfType);
  441.     }
  442.     RECOVER
  443.     {
  444.         theErr = gFailError;
  445.         goto ReturnErrorCode;
  446.     }
  447.     ENDTRY
  448.  
  449. ReturnErrorCode:
  450.     return theErr;
  451. }
  452.  
  453.  
  454. pascal OSErr TAppleObjectDispatcher::OSLCompareObjectsHandler(DescType operation,
  455.                                          const AEDesc *obj1,
  456.                                          const AEDesc *obj2,
  457.                                          Boolean *answer)
  458. {
  459.     OSErr    result = noErr;
  460.  
  461.     TRY
  462.     {
  463.         *answer = GetDispatcher()->CompareObjects(operation, *obj1, *obj2);
  464.     }
  465.     RECOVER
  466.     {
  467.         result = gFailError;
  468.         goto ReturnErrorCode;
  469.     }
  470.     ENDTRY
  471.  
  472. ReturnErrorCode:
  473.     return result;
  474. }
  475.  
  476.  
  477. pascal OSErr TAppleObjectDispatcher::OSLDisposeTokenHandler(AEDesc* unneededToken)
  478. {
  479.     OSErr    result = noErr;
  480.  
  481.     TRY
  482.     {
  483.         GetDispatcher()->DisposeToken(*unneededToken);
  484.     }
  485.     RECOVER
  486.     {
  487.         result = gFailError;
  488.         goto ReturnErrorCode;
  489.     }
  490.     ENDTRY
  491.  
  492. ReturnErrorCode:
  493.     return result;
  494. }
  495.  
  496.  
  497. void TAppleObjectDispatcher::InstallAppleEventHandler(AEEventClass theClass,
  498.                                                      AEEventID theID,
  499.                                                      long refCon)
  500. {
  501.     FailOSErr(AEInstallEventHandler(theClass, theID,
  502.                                     (EventHandlerProcPtr) TAppleObjectDispatcher::AppleEventHandler,
  503.                                     refCon, false));
  504. }
  505.  
  506.  
  507. //--------------------------------------------------------------------------------
  508. // MAppleObject
  509. //--------------------------------------------------------------------------------
  510.  
  511. Boolean MAppleObject::fgInited = false;
  512. MAppleObject* MAppleObject::fgDefaultAppleObject = nil;
  513.  
  514.  
  515. MAppleObject::MAppleObject()
  516. {
  517. }
  518.  
  519.  
  520. MAppleObject::MAppleObject(const MAppleObject& /* copy */)
  521. {
  522. }
  523.  
  524.  
  525. MAppleObject::~MAppleObject()
  526. {
  527.     if (MAppleObject::GetDefaultAppleObject() == this)
  528.         MAppleObject::SetDefaultAppleObject(nil);
  529.  
  530.     TAppleObjectDispatcher::GetDispatcher()->SetTokenObjectDisposal(this, false);
  531. }
  532.  
  533.  
  534. MAppleObject& MAppleObject::operator=(const MAppleObject& /* assignTo */)
  535. {
  536.     return *this;
  537. }
  538.  
  539.  
  540. void MAppleObject::InitAppleObject(TAppleObjectDispatcher* dispatcher)
  541. {
  542.     // create a dispatcher if one wasn't passed in
  543.     if (dispatcher == nil)
  544.     {
  545.         dispatcher = new TAppleObjectDispatcher();
  546.         FailNIL(dispatcher);
  547.     }
  548.  
  549.     // Install the dispatcher
  550.     dispatcher->Install();
  551.  
  552.     fgInited = true;
  553. }
  554.  
  555.  
  556. long MAppleObject::CountContainedObjects(DescType /* ofType */)
  557. {
  558.     return 0;
  559. }
  560.  
  561.  
  562. Boolean MAppleObject::CompareAppleObjects(DescType /* operation */,
  563.                                           const MAppleObject& /* toWhat */)
  564. {
  565.     return false;
  566. }
  567.  
  568.  
  569. void MAppleObject::DoAppleEvent(const AppleEvent& /* message */,
  570.                                 AppleEvent& /* reply */, long /* refCon */)
  571. {
  572.     FailOSErr(errAEEventNotHandled);
  573. }
  574.  
  575.  
  576. MAppleObject* MAppleObject::GetContainedObject(DescType /* desiredType */,
  577.                                                DescType /* keyForm */,
  578.                                                const AEDesc& /* keyData */,
  579.                                                Boolean& /* needDisposal */)
  580. {
  581.     return nil;
  582. }
  583.  
  584.  
  585. void MAppleObject::GotRequiredParameters(const AppleEvent& theAppleEvent)
  586. {
  587.     // look for the keyMissedKeywordAttr, just to see if it's there
  588.     DescType    returnedType;
  589.     Size        actualSize;
  590.     OSErr theErr = AEGetAttributePtr(&theAppleEvent, keyMissedKeywordAttr,
  591.                                      typeWildCard, &returnedType, nil, 0,
  592.                                      &actualSize);
  593.  
  594.     if (theErr == noErr)
  595.     {
  596.         // Since the attribute exists, we missed a parameter somewhere.
  597.         FailOSErr(errAEParamMissed);
  598.     }
  599.     else if (theErr != errAEDescNotFound)
  600.     {
  601.         // The only error that is OK is to say that the descriptor was not
  602.         // found (indicating that we got all the parameters).  If any other
  603.         // error occurred, throw it.
  604.         FailOSErr(theErr);
  605.     }
  606. }
  607.  
  608.  
  609. void MAppleObject::SetDefaultAppleObject(MAppleObject* defaultObject)
  610. {
  611.     fgDefaultAppleObject = defaultObject;
  612. }
  613.